package edu.washington.ling.syntric.consistency;

import java.util.LinkedList;
import java.util.List;

import edu.washington.ling.syntric.struct.tree.Token;
import edu.washington.ling.syntric.struct.tree.Tree;
import edu.washington.ling.syntric.util.Pair;
import edu.washington.ling.syntric.util.TreeUtils;

public class LongDistanceMovementRule extends ConsistencyRule {
	
	@Override
	public void apply(Tree ds) {
		Token dsRoot = ds.getDSRoot();
		apply(dsRoot, ds);
	}
	
	public void apply(Token t, Tree ds) {
		List<Token> children = new LinkedList<Token>(t.getDSDependents());
		for (Token child: children) {
			apply(child, ds);
		}
		int pos = ds.getTokenPosition(t);
		Pair<Integer, Integer> span = 
				new Pair<Integer, Integer>(pos, pos);
		List<Token> leftChildren = TreeUtils.getLeftDSChildren(t, ds);
		TreeUtils.sortTokens(leftChildren, ds, true);
		for (Token leftChild: leftChildren) {
			Pair<Integer, Integer> childSpan = TreeUtils.getSpan(leftChild, ds);
			if (childSpan.getRight() < span.getLeft() - 1) {
				if (t.hasDSHead()) {
					if (!leftChild.isScrambledLongDistance()) {
						leftChild.setScrambledLongDistance(true);
						int index = ds.nextCoindex();
						Token ec = ConsistencyUtils.createMovementEC("SCR", leftChild.getDSRelation(), index);
						leftChild.setDSTargetIndex(index);
						t.addECDependent(ec);
					}
					leftChild.setDSHead(t.getDSHead());
					t.removeDSDependent(leftChild);
					t.getDSHead().addDSDependent(leftChild);
				} 
			} else {
				span.setLeft(childSpan.getLeft());
			}
		}
		List<Token> rightChildren = TreeUtils.getRightDSChildren(t, ds);
		TreeUtils.sortTokens(rightChildren, ds);
		for (Token rightChild: rightChildren) {
			Pair<Integer, Integer> childSpan = TreeUtils.getSpan(rightChild, ds);
			if (span.getRight() < childSpan.getLeft() - 1) {
				if (t.hasDSHead()) {
					if (!rightChild.isExtraposed()) {
						rightChild.setExtraposed(true);
						int index = ds.nextCoindex();
						Token ec = ConsistencyUtils.createMovementEC("EXTR", rightChild.getDSRelation(), index);
						rightChild.setDSTargetIndex(index);
						t.addECDependent(ec);
					}
					rightChild.setDSHead(t.getDSHead());
					t.removeDSDependent(rightChild);
					t.getDSHead().addDSDependent(rightChild);
				} 
			} else {
				span.setRight(childSpan.getRight());
			}
		}
	}

	
}
